/*
 * Utilities, such as CLI/STI, and memory functions
*/

#include "util.h"
#include "video.h"

// enable interrupts
void enable() { __asm__ __volatile__("sti"); }
// disable interrupts
void disable() { __asm__ __volatile__("cli"); }

/*
 * procedure: memcpy
 * description: copies data from one area of memory to another
*/
void *memcpy(void *dest, const void *src, int count)
{
    const char *sp = (const char *)src;
    char *dp = (char *)dest;
    while(count--) *dp++ = *sp++;
    return dest;
}

/*
 * procedure: memset
 * description: sets an area of memory equal to a value
*/
void *memset(void *dest, char val, int count)
{
    char *temp = (char *)dest;
    while(count--) *temp++ = val;
    return dest;
}

/*
 * procedure: memsetw
 * description: sets an area of memory equal to a value
*/
unsigned short *memsetw(unsigned short *dest, unsigned short val, int count)
{
    unsigned short *temp = (unsigned short *)dest;
    while(count--) *temp++ = val;
    return dest;
}

/*
 * procedure: strlen
 * description: returns the length of the string
*/
int strlen(const char *str)
{
    int i = 0;
    while(*str++ != '\0') i++;
    return i;
}

/*
 * procedure: strcmp
 * description: compares two strings
*/
int strcmp(char *str1, char *str2)
{
	int i = 0;
	int failed = 0;
	while(str1[i] != '\0' && str2[i] != '\0')
	{
		if(str1[i] != str2[i])
		{
			failed = 1;
			break;
		}
		i++;
	}
	// why did the loop exit?
	if( (str1[i] == '\0' && str2[i] != '\0') || (str1[i] != '\0' && str2[i] == '\0') )
		failed = 1;
  
	return failed;
}

/* strcpy */
char *strcpy(char *dest, const char *src)
{
    do
    {
      *dest++ = *src++;
    }
    while (*src != 0);
}

/* strcat */
char *strcat(char *dest, const char *src)
{
    while (*dest != 0)
    {
        *dest = *dest++;
    }

    do
    {
        *dest++ = *src++;
    }
    while (*src != 0);
    return dest;
}

/*
 * procedure: inportb
 * description: reads a byte from the port
*/
unsigned char inportb (unsigned short _port)
{
    unsigned char rv;
    __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
    return rv;
}

/*
 * procedure: outportb
 * description: sends a byte to a port
*/
void outportb (unsigned short _port, unsigned char _data)
{
    __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}

/*
 * procedure: panic
 * description: outputs a string, disables interrupts
 *	and spins its wheels
*/
void panic(char *text)
{
	puts("KERNEL PANIC(");
	puts(text);
	puts(")");
	disable();
	__asm__ __volatile__("hlt");
}

/*
 * procedure: reboot
 * description: reboots the machine
 * notes:
 *	clears interrupts, sends reboot signal
 *	to the keyboard controller, and if it doesn't
 *	reboot, it spins its wheels

*/
void reboot()
{
	unsigned flush;
	
	disable();
	
	// flush the keyboard buffer
	do
	{
		flush = inportb(0x64);
		if((flush & 0x01) != 0)
		{
			inportb(0x60);
			continue;
		}
	}while((flush & 0x02) != 0);
	
	// send the reboot command
	outportb(0x64, 0xFE);
	
	// if we do get here, then just spin our wheels
	while(1) ;
}
